package com.wlyuan.index.domain.source.adapter;


import com.wlyuan.index.api.dto.waybill.WaybillArgumentsDTO;
import com.wlyuan.index.api.dto.waybill.WaybillIndexDTO;
import com.wlyuan.index.domain.index.valueobj.Carrier;
import com.wlyuan.index.domain.index.valueobj.Customer;
import com.wlyuan.transport.dto.query.WaybillConsigneeDTO;
import com.wlyuan.transport.dto.query.WaybillCustomerDTO;
import com.wlyuan.transport.dto.query.WaybillEventDTO;
import com.wlyuan.transport.dto.query.WaybillRequirementDTO;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * 运单事件详情（对应运输服务的 WaybillEventDTO类）
 *
 * @author liuqingqing
 */
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Data
public class WaybillAdapter extends WaybillIndexDTO implements Serializable {

    @Mapper
    public interface Assembler {
        void assemble(@MappingTarget WaybillIndexDTO waybill, WaybillIndexDTO source);

        @Mappings({
                @Mapping(source = "goodsCategory", target = "cargoType"),
                @Mapping(source = "onLoad", target = "load"),
                @Mapping(source = "offLoad", target = "unload"),
                @Mapping(source = "shipMode", target = "distanceType"),
                @Mapping(source = "chargeMode", target = "billingMode"),
                @Mapping(source = "pricingUnit", target = "billingUnit"),
                @Mapping(source = "vehicleType", target = "vehicleModel"),
                @Mapping(source = "vehicleCount", target = "vehicleQuantity"),
        })
        WaybillArgumentsDTO assemble(WaybillRequirementDTO source);

        @Mappings({
                @Mapping(source = "transportRequirement", target = "arguments")
        })
        WaybillIndexDTO translate(WaybillEventDTO source);

        default Boolean intToBool(Integer source) {
            if (null == source) {
                return null;
            }

            return 0 != source;
        }
    }

    private static final Assembler ASSEMBLER = Mappers.getMapper(Assembler.class);

    public WaybillAdapter(WaybillIndexDTO index) {
        ASSEMBLER.assemble(this, index);
    }

    private boolean isNamedCity(String city) {
        return StringUtils.isNotEmpty(city) && !"市辖区".equals(city);
    }

    private void addKeyword(List<String> keywords, String keyword) {
        if (StringUtils.isEmpty(keyword)) {
            return;
        }
        if (!keywords.contains(keyword)) {
            keywords.add(keyword);
        }
    }

    public List<String> getKeywords() {
//        contractNo,fromAddress.city,toAddress.city,consigneeName,fromAddress.contactName,customerName,toAddress.contactName
        List<String> keywords = new ArrayList<>();
        if (StringUtils.isNotEmpty(this.getContractNo())) {
            keywords.add(this.getContractNo());
        }

        Optional.ofNullable(this.getConsignee())
                .map(WaybillConsigneeDTO::getConsigneeName)
                .filter(StringUtils::isNotEmpty)
                .ifPresent(keywords::add);

        Optional.ofNullable(this.getCustomer())
                .map(WaybillCustomerDTO::getCustomerName)
                .filter(StringUtils::isNotEmpty)
                .ifPresent(keywords::add);

        Optional.ofNullable(this.getFromAddress()).ifPresent(address -> {
            if (isNamedCity(address.getCity())) {
                addKeyword(keywords, address.getCity());
            } else {
                addKeyword(keywords, address.getProvince());
            }
        });

        Optional.ofNullable(this.getToAddress()).ifPresent(address -> {
            if (isNamedCity(address.getCity())) {
                addKeyword(keywords, address.getCity());
            } else {
                addKeyword(keywords, address.getProvince());
            }
        });

        Optional.ofNullable(this.getFromContact())
                .ifPresent(contact -> addKeyword(keywords, contact.getContactName()));

        Optional.ofNullable(this.getToContact())
                .ifPresent(contact -> addKeyword(keywords, contact.getContactName()));

        return keywords;
    }

    public boolean isOriginal() {
        return NumberUtils.INTEGER_ONE.equals(this.getIsRootWaybill());
    }

    private boolean isOnlineCarrier() {
        return Optional.ofNullable(this.getCarrier())
                .map(carrier -> Carrier.isOnline(carrier.getCarrierType()))
                .orElse(false);
    }

    private boolean isOnlineCustomer() {
        return Optional.ofNullable(this.getCustomer())
                .map(customer -> Customer.isOnline(customer.getCustomerType()))
                .orElse(false);
    }

    public boolean hasUpstream() {
        return null != this.getUpstream();
    }

    public boolean hasDownstream() {
        return null != this.getDownstream();
    }

    public boolean hasCombine() {
        return BooleanUtils.isTrue(this.getCombined()) && null != this.getCombineId();
    }

    public static WaybillIndexDTO translate(WaybillEventDTO source) {
        return ASSEMBLER.translate(source);
    }
}
